home *** CD-ROM | disk | FTP | other *** search
/ The Arsenal Files 8 / The Arsenal Files Collection #8 (Arsenal Computer) (1996).ISO / prg_casm / snpd9611.zip / GETOPTS.C < prev    next >
C/C++ Source or Header  |  1996-11-24  |  18KB  |  567 lines

  1. .I 0 14
  2. /* +++Date last modified: 24-Nov-1996 */
  3.  
  4. /************************************************************************/
  5. /*                                                                      */
  6. /*  GETOPTS.C - Universal command line options parser                   */
  7. /*                                                                      */
  8. /*  Original Copyright 1990-96 by Robert B. Stout as part of            */
  9. /*  the MicroFirm Function Library (MFL)                                */
  10. /*                                                                      */
  11. /*  The user is granted a free limited license to use this source file  */
  12. /*  to create royalty-free programs, subject to the terms of the        */
  13. /*  license restrictions specified in the LICENSE.MFL file.             */
  14. /*                                                                      */
  15. /************************************************************************/
  16. .D 1 8
  17. .I 12 4
  18. #include <limits.h>
  19. #include "sniptype.h"
  20. #include "filnames.h"
  21. #include "errors.h"
  22. .I 13 2
  23. #include "snipmath.h"
  24. #include "minmax.h"
  25. .D 16 1
  26. .I 18 13
  27. int         xargc = 0;
  28. char       *xargv[MAX_XARGS]        = {NULL};
  29. Boolean_T   getopts_range_err       = False_;
  30. Boolean_T   xargs_on                = True_;
  31.  
  32. static FILE *rspfile = NULL;
  33. static int   count = 0, argidx = 0;
  34.  
  35. enum proc_stat { PSerror = -1, PSok, PSliteral};
  36.  
  37. static Boolean_T      PASCAL bounds(struct Option_Tag *);
  38. static enum proc_stat PASCAL swProc(char *swStr);
  39. static void           PASCAL argProc(char *argStr);
  40. .D 19 2
  41. .I 28 7
  42. **  Returns: Number of options specified or Error_
  43. **
  44. **  Notes: 1. Your program should declare the global options[] array which
  45. **            specifies all options recognized by getopts().
  46. **
  47. **         2. Out of range data are coerced into range and getopts_range_err
  48. **            is set True_.
  49. .D 29 4
  50. .I 36 2
  51.       int i;
  52.       Boolean_T scanning = True_;
  53. .D 37 2
  54. .I 39 3
  55.       char rspfname[FILENAME_MAX];
  56.       char newarg[256];
  57.       enum proc_stat ps;
  58. .I 42 20
  59.       for (i = 1, count = 0; i < argc; )
  60.       {
  61.             /*
  62.             ** If necessary, open a response file
  63.             */
  64.  
  65.             if (scanning && !rspfile && '@' == argv[i][0])
  66.             {
  67.                   rspfile = cant(&argv[i][1], "r");
  68.                   --xargc;
  69.                   continue;
  70.             }
  71.  
  72.             /*
  73.             ** Get the next argument
  74.             */
  75.  
  76.             if (rspfile)
  77.             {
  78.                   if (NULL == fgets(newarg, 256, rspfile))
  79. .D 43 15
  80. .I 58 2
  81.                         rspfile = NULL;
  82.                         ++i;
  83. .D 59 61
  84. .I 121 21
  85.                   else
  86.                   {
  87.                         if ('\n' == LAST_CHAR(newarg))
  88.                               LAST_CHAR(newarg) = NUL;
  89.                   }
  90.             }
  91.             else
  92.             {
  93.                   strcpy(newarg, argv[i++]);
  94.             }
  95.  
  96.             /*
  97.             ** Per Unix tradition, back-to-back switch characters signify
  98.             ** the end of the switches
  99.             */
  100.  
  101.             if ((2 == strlen(newarg)) && strchr("-/", newarg[0]) &&
  102.                   strchr("-/", newarg[1]))
  103.             {
  104.                   scanning = False_;
  105.                   if (!rspfile)
  106. .D 122 20
  107. .I 142 19
  108.                   continue;
  109.             }
  110.  
  111.             if (scanning && (strchr("-/", newarg[0])))
  112.             {
  113.                   ps = swProc(newarg);
  114.  
  115.                   if (PSerror == ps)
  116.                         return Error_;
  117.  
  118.                   if (PSok == ps)
  119.                         continue;
  120.             }
  121.  
  122.             /*
  123.             ** If we got here, newarg must be an argument or filename
  124.             */
  125.  
  126.             argProc(newarg);
  127. .D 143 12
  128. .I 158 437
  129. /*
  130. **  Static function to process switch statements
  131. **
  132. **  Parameters: 1 - argv[i] containing the switch
  133. **
  134. **  Returns: PSok      if switch successful
  135. **           PSerror   if invalid
  136. **           PSliteral if literal (non-switch) argument
  137. */
  138.  
  139. static enum proc_stat PASCAL swProc(char *swStr)
  140. {
  141.       struct Option_Tag *ptr;
  142.       Boolean_T searching;
  143.       unsigned short byte_var;
  144.       char *arg_ptr;
  145.  
  146.       /*
  147.       ** Found a switch - If the 2nd character is also a switch
  148.       ** character. If so, then it's a literal and is skipped
  149.       */
  150.  
  151.       if (strchr("-/@", swStr[1]))
  152.             return PSliteral;
  153.  
  154.       for (ptr = options, searching = True_; searching; ++ptr)
  155.       {
  156.             if (!ptr->case_sense)
  157.             {
  158.                   ptr->letter = toupper(ptr->letter);
  159.                   swStr[1]    = toupper(swStr[1]);
  160.             }
  161.             if ((int)swStr[1] == ptr->letter) switch (ptr->type)
  162.             {
  163.             case Boolean_Tag:
  164.                   if ('-' == swStr[2])
  165.                         *((Boolean_T *)(ptr->buf)) = False_;
  166.                   else  *((Boolean_T *)(ptr->buf)) = True_;
  167.                   searching = False_;
  168.                   break;
  169.  
  170.             case Byte_Tag:
  171.                   if (!swStr[2])
  172.                   {
  173.                         if (ptr->Default)
  174.                               arg_ptr = ptr->Default;
  175.                         else  return PSerror;
  176.                   }
  177.                   else  arg_ptr = &swStr[2];
  178.  
  179.                   sscanf(arg_ptr, "%hx", &byte_var);
  180.                   *((char *)(ptr->buf)) = (unsigned char)(byte_var & 0xff);
  181.                   bounds(ptr);
  182.                   searching = False_;
  183.                   break;
  184.  
  185.             case Int_Tag:
  186.                   if (!swStr[2])
  187.                   {
  188.                         if (ptr->Default)
  189.                               arg_ptr = ptr->Default;
  190.                         else  return PSerror;
  191.                   }
  192.                   else  arg_ptr = &swStr[2];
  193.  
  194.                   *((int *)(ptr->buf)) = (int)(dround(getopts_eval(arg_ptr)));
  195.                   bounds(ptr);
  196.                   searching = False_;
  197.                   break;
  198.  
  199.             case Short_Tag:
  200.                   if (!swStr[2])
  201.                   {
  202.                         if (ptr->Default)
  203.                               arg_ptr = ptr->Default;
  204.                         else  return PSerror;
  205.                   }
  206.                   else  arg_ptr = &swStr[2];
  207.  
  208.                   *((short *)(ptr->buf)) =
  209.                         (short)(dround(getopts_eval(arg_ptr)));
  210.                   bounds(ptr);
  211.                   searching = False_;
  212.                   break;
  213.  
  214.             case Word_Tag:
  215.                   if (!swStr[2])
  216.                   {
  217.                         if (ptr->Default)
  218.                               arg_ptr = ptr->Default;
  219.                         else  return PSerror;
  220.                   }
  221.                   else  arg_ptr = &swStr[2];
  222.  
  223.                   sscanf(arg_ptr, "%hx", (unsigned short *)(ptr->buf));
  224.                   bounds(ptr);
  225.                   searching = False_;
  226.                   break;
  227.  
  228.             case Long_Tag:
  229.                   if (!swStr[2])
  230.                   {
  231.                         if (ptr->Default)
  232.                               arg_ptr = ptr->Default;
  233.                         else  return PSerror;
  234.                   }
  235.                   else  arg_ptr = &swStr[2];
  236.  
  237.                   *((long *)(ptr->buf)) =
  238.                         (long)(dround(getopts_eval(arg_ptr)));
  239.                   bounds(ptr);
  240.                   searching = False_;
  241.                   break;
  242.  
  243.             case DWord_Tag:
  244.                   if (!swStr[2])
  245.                   {
  246.                         if (ptr->Default)
  247.                               arg_ptr = ptr->Default;
  248.                         else  return PSerror;
  249.                   }
  250.                   else  arg_ptr = &swStr[2];
  251.  
  252.                   sscanf(arg_ptr, "%lx", (unsigned long *)(ptr->buf));
  253.                   bounds(ptr);
  254.                   searching = False_;
  255.                   break;
  256.  
  257.             case Float_Tag:
  258.                   if (!swStr[2])
  259.                   {
  260.                         if (ptr->Default)
  261.                               arg_ptr = ptr->Default;
  262.                         else  return PSerror;
  263.                   }
  264.                   else  arg_ptr = &swStr[2];
  265.  
  266.                   *((double *)(ptr->buf)) = (double)getopts_eval(arg_ptr);
  267.                   bounds(ptr);
  268.                   searching = False_;
  269.                   break;
  270.  
  271.             case DFloat_Tag:
  272.                   if (!swStr[2])
  273.                   {
  274.                         if (ptr->Default)
  275.                               arg_ptr = ptr->Default;
  276.                         else  return PSerror;
  277.                   }
  278.                   else  arg_ptr = &swStr[2];
  279.  
  280.                   *((double *)(ptr->buf)) = (double)getopts_eval(arg_ptr);
  281.                   bounds(ptr);
  282.                   searching = False_;
  283.                   break;
  284.  
  285.             case String_Tag:
  286.                   if (!swStr[2] && ptr->Default)
  287.                         strcpy(ptr->buf, (char *)(ptr->Default));
  288.                   else  strcpy(ptr->buf, &swStr[2]);
  289.  
  290.                   searching = False_;
  291.                   break;
  292.  
  293.             default:
  294.                   return Error_;
  295.             }
  296.       }
  297.       ++count;
  298.       if (!rspfile)
  299.             --xargc;
  300.  
  301.       return PSok;
  302. }
  303.  
  304. /*
  305. **  Static function to process arguments
  306. */
  307.  
  308. static void PASCAL argProc(char *argStr)
  309. {
  310.       DOSFileData ff;
  311.  
  312.       /* If no wildcards or ignoring wildcards, just copy it */
  313.  
  314.       if (!xargs_on || !has_wild(argStr))
  315.       {
  316.             xargv[argidx] = malloc(strlen(argStr) + 1);
  317.             if (NULL == xargv[argidx])
  318.                   ErrExit("Out of memory");
  319.             strcpy(xargv[argidx], argStr);
  320.             ++argidx;
  321.             return;
  322.       }
  323.       else  /* Expand wildcards, if possible                      */
  324.       {
  325.             if (Success_ == FIND_FIRST(argStr, _A_ANY, &ff))
  326.             {
  327.                   char path[FILENAME_MAX];
  328.                   char *p;
  329.  
  330.                   /* Save the path for re-attachment              */
  331.  
  332.                   fnSplit(argStr, NULL, path, NULL, NULL, NULL, NULL);
  333.  
  334.                   --xargc;    /* We add stuff in the loop, so back up   */
  335.                   do
  336.                   {                             
  337.                         xargv[argidx] = malloc(strlen(ff_name(&ff))
  338.                                                + strlen(path) + 2);
  339.                         if (NULL == xargv[argidx])
  340.                               ErrExit("Out of memory");
  341.                         fnMerge(xargv[argidx], NULL, path, NULL, ff_name(&ff),
  342.                                 NULL, NULL);
  343.                         ++argidx;
  344.                         ++xargc;
  345.  
  346.                   } while (Success_ == FIND_NEXT(&ff));
  347.                   FIND_END(&ff);
  348.             }
  349.       }
  350. }
  351.  
  352. /*
  353. **  Assure new data are within specified ranges, return non-zero if coerced
  354. */
  355.  
  356. static Boolean_T PASCAL bounds(struct Option_Tag *option)
  357. {
  358.       Boolean_T coerced = False_;
  359.       union {
  360.             unsigned char     B;
  361.             int               I;
  362.             short             S;
  363.             unsigned short    W;
  364.             long              L;
  365.             unsigned long     DW;
  366.             float             F;
  367.             double            D;
  368.       } tmp, val;
  369.       
  370.       switch(option->type)
  371.       {
  372.       case Byte_Tag:
  373.             tmp.B = *((unsigned char *)(option->buf));
  374.             if (option->max)
  375.             {
  376.                   sscanf(option->max, "%hx", &val.B);
  377.                   tmp.B = min(tmp.B, val.B);
  378.             }
  379.             if (option->min)
  380.             {
  381.                   sscanf(option->min, "%hx", &val.B);
  382.                   tmp.B = max(tmp.B, val.B);
  383.             }
  384.             if (*((unsigned char *)(option->buf)) != tmp.B)
  385.             {
  386.                   getopts_range_err = True_;
  387.                   *((unsigned char *)(option->buf)) = tmp.B;
  388.                   coerced = True_;
  389.             }
  390.             break;
  391.  
  392.       case Int_Tag:
  393.             tmp.I = *((int *)(option->buf));
  394.             if (option->max)
  395.             {
  396.                   val.D = dround(getopts_eval(option->max));
  397.                   if (val.D > (double)INT_MAX)
  398.                         val.I = INT_MAX;
  399.                   else  val.I = (int)val.D;
  400.                   tmp.I = min(tmp.I, val.I);
  401.             }
  402.             if (option->min)
  403.             {
  404.                   val.D = dround(getopts_eval(option->min));
  405.                   if (val.D < (double)INT_MIN)
  406.                         val.I = INT_MIN;
  407.                   else  val.I = (int)val.D;
  408.                   tmp.I = max(tmp.I, val.I);
  409.             }
  410.             if (*((int *)(option->buf)) != tmp.I)
  411.             {
  412.                   getopts_range_err = True_;
  413.                   *((int *)(option->buf)) = tmp.I;
  414.                   coerced = True_;
  415.             }
  416.             break;
  417.  
  418.       case Short_Tag:
  419.             tmp.S = *((short *)(option->buf));
  420.             if (option->max)
  421.             {
  422.                   val.D = dround(getopts_eval(option->max));
  423.                   if (val.D > (double)SHRT_MAX)
  424.                         val.S = SHRT_MAX;
  425.                   else  val.S = (short)val.D;
  426.                   tmp.S = min(tmp.I, val.I);
  427.             }
  428.             if (option->min)
  429.             {
  430.                   val.D = dround(getopts_eval(option->min));
  431.                   if (val.D < (double)SHRT_MIN)
  432.                         val.S = SHRT_MIN;
  433.                   else  val.S = (short)val.D;
  434.                   tmp.S = max(tmp.I, val.I);
  435.             }
  436.             if (*((short *)(option->buf)) != tmp.S)
  437.             {
  438.                   getopts_range_err = True_;
  439.                   *((short *)(option->buf)) = tmp.I;
  440.                   coerced = True_;
  441.             }
  442.             break;
  443.  
  444.       case Word_Tag:
  445.             tmp.W = *((unsigned short *)(option->buf));
  446.             if (option->max)
  447.             {
  448.                   sscanf(option->max, "%hx", &val.W);
  449.                   tmp.W = min(tmp.W, val.W);
  450.             }
  451.             if (option->min)
  452.             {
  453.                   sscanf(option->min, "%hx", &val.W);
  454.                   tmp.W = max(tmp.W, val.W);
  455.             }
  456.             if (*((unsigned short *)(option->buf)) != tmp.W)
  457.             {
  458.                   getopts_range_err = True_;
  459.                   *((unsigned short *)(option->buf)) = tmp.W;
  460.                   coerced = True_;
  461.             }
  462.             break;
  463.  
  464.       case Long_Tag:
  465.             tmp.L = *((long *)(option->buf));
  466.             if (option->max)
  467.             {
  468.                   val.D = dround(getopts_eval(option->max));
  469.                   if (val.D > (double)LONG_MAX)
  470.                         val.L = LONG_MAX;
  471.                   else  val.L = (long)val.D;
  472.                   tmp.L = min(tmp.L, val.L);
  473.             }
  474.             if (option->min)
  475.             {
  476.                   val.D = dround(getopts_eval(option->min));
  477.                   if (val.D < (double)LONG_MIN)
  478.                         val.L = LONG_MIN;
  479.                   else  val.L = (int)val.D;
  480.                   tmp.L = max(tmp.L, val.L);
  481.             }
  482.             if (*((long *)(option->buf)) != tmp.L)
  483.             {
  484.                   getopts_range_err = True_;
  485.                   *((long *)(option->buf)) = tmp.L;
  486.                   coerced = True_;
  487.             }
  488.             break;
  489.  
  490.       case DWord_Tag:
  491.             tmp.DW = *((unsigned long *)(option->buf));
  492.             if (option->max)
  493.             {
  494.                   sscanf(option->max, "%lx", &val.DW);
  495.                   tmp.DW = min(tmp.DW, val.DW);
  496.             }
  497.             if (option->min)
  498.             {
  499.                   sscanf(option->min, "%hx", &val.DW);
  500.                   tmp.DW = max(tmp.DW, val.DW);
  501.             }
  502.             if (*((unsigned long *)(option->buf)) != tmp.DW)
  503.             {
  504.                   getopts_range_err = True_;
  505.                   *((unsigned long *)(option->buf)) = tmp.DW;
  506.                   coerced = True_;
  507.             }
  508.             break;
  509.  
  510.       case Float_Tag:
  511.             tmp.F = *((float *)(option->buf));
  512.             if (option->max)
  513.             {
  514.                   val.F = (float)getopts_eval(option->max);
  515.                   tmp.F = min(tmp.F, val.F);
  516.             }
  517.             if (option->min)
  518.             {
  519.                   val.F = (float)getopts_eval(option->min);
  520.                   tmp.F = max(tmp.F, val.F);
  521.             }
  522.             if (*((float *)(option->buf)) != tmp.F)
  523.             {
  524.                   getopts_range_err = True_;
  525.                   *((float *)(option->buf)) = tmp.F;
  526.                   coerced = True_;
  527.             }
  528.             break;
  529.  
  530.       case DFloat_Tag:
  531.             tmp.D = *((double *)(option->buf));
  532.             if (option->max)
  533.             {
  534.                   val.D = getopts_eval(option->max);
  535.                   tmp.D = min(tmp.D, val.D);
  536.             }
  537.             if (option->min)
  538.             {
  539.                   val.D = getopts_eval(option->min);
  540.                   tmp.D = max(tmp.D, val.D);
  541.             }
  542.             if (*((double *)(option->buf)) != tmp.D)
  543.             {
  544.                   getopts_range_err = True_;
  545.                   *((double *)(option->buf)) = tmp.D;
  546.                   coerced = True_;
  547.             }
  548.             break;
  549.       }
  550.  
  551.       return coerced;
  552. }
  553.  
  554. /*
  555. **  Simplified evaluate() call - returns double or aborts
  556. */
  557.  
  558. double getopts_eval(char *str)
  559. {
  560.       double retval;
  561.  
  562.       if (Success_ == evaluate(str, &retval))
  563.             return retval;
  564.       else  ErrExit("Error evlauating \"%s\" - aborting\n", str);
  565. }
  566. .D 159 44
  567.